/**
 * Java数组和字符串教学案例
 * 本案例演示了Java中数组和字符串的使用方法、常见操作和注意事项
 */
public class ArrayAndStringExample {
    
    public static void main(String[] args) {
        ArrayAndStringExample example = new ArrayAndStringExample();
        
        example.demonstrateOneDimensionalArray();    // 一维数组演示
        example.demonstrateMultiDimensionalArray();  // 多维数组演示
        example.demonstrateArrayTraversal();         // 数组遍历演示
        example.demonstrateArraysUtility();          // Arrays工具类演示
        example.demonstrateArrayAlgorithms();        // 数组常见算法演示
        example.demonstrateStringBasics();           // String类演示
        example.demonstrateStringBufferBuilder();    // StringBuffer和StringBuilder演示
        example.demonstrateStringOperations();       // 字符串操作演示
        example.demonstrateRegex();                  // 正则表达式演示
        example.demonstrateStringProcessing();       // 字符串处理技巧演示
    }
    
    /**
     * 演示一维数组的声明、初始化和使用
     * 难点：数组下标越界异常(ArrayIndexOutOfBoundsException)
     * 注意事项：
     * 1. 数组一旦创建，大小不可变
     * 2. 数组元素有默认值（数值型为0，布尔型为false，引用型为null）
     * 3. 数组下标从0开始，最大下标为长度-1
     */
    public void demonstrateOneDimensionalArray() {
        System.out.println("=== 一维数组的声明、初始化和使用 ===");
        
        // 数组的声明方式1：先声明后分配内存
        int[] numbers1;
        numbers1 = new int[5]; // 创建长度为5的整型数组，默认值都为0
        
        // 数组的声明方式2：声明同时初始化
        int[] numbers2 = new int[5];
        
        // 数组的声明方式3：静态初始化
        int[] numbers3 = {10, 20, 30, 40, 50};
        
        // 数组的声明方式4：简化静态初始化（只能在声明时使用）
        int[] numbers4 = {1, 2, 3, 4, 5};
        
        // 数组元素的访问和赋值
        numbers2[0] = 100;
        numbers2[1] = 200;
        numbers2[2] = 300;
        numbers2[3] = 400;
        numbers2[4] = 500;
        
        System.out.println("numbers3数组元素:");
        for (int i = 0; i < numbers3.length; i++) {
            System.out.println("numbers3[" + i + "] = " + numbers3[i]);
        }
        
        // 难点演示：数组下标越界
        try {
            int value = numbers3[5]; // 尝试访问不存在的下标，会产生ArrayIndexOutOfBoundsException
            System.out.println("value = " + value);
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("捕获到数组下标越界异常: " + e.getMessage());
        }
        
        System.out.println("数组numbers3的长度: " + numbers3.length);
        System.out.println();
    }
    
    /**
     * 演示多维数组的使用
     * 难点：不规则数组的理解和使用
     * 注意事项：
     * 1. 二维数组可以看作是"数组的数组"
     * 2. 多维数组的每一维都可以有不同的长度（不规则数组）
     */
    public void demonstrateMultiDimensionalArray() {
        System.out.println("=== 多维数组演示 ===");
        
        // 规则二维数组的声明和初始化
        int[][] matrix1 = new int[3][4]; // 3行4列的二维数组
        
        // 静态初始化二维数组
        int[][] matrix2 = {
            {1, 2, 3},
            {4, 5, 6},
            {7, 8, 9}
        };
        
        // 不规则数组的创建
        int[][] irregularArray = new int[3][];
        irregularArray[0] = new int[2];  // 第一行有2个元素
        irregularArray[1] = new int[4];  // 第二行有4个元素
        irregularArray[2] = new int[3];  // 第三行有3个元素
        
        // 为不规则数组赋值
        irregularArray[0][0] = 1;
        irregularArray[0][1] = 2;
        
        irregularArray[1][0] = 3;
        irregularArray[1][1] = 4;
        irregularArray[1][2] = 5;
        irregularArray[1][3] = 6;
        
        irregularArray[2][0] = 7;
        irregularArray[2][1] = 8;
        irregularArray[2][2] = 9;
        
        // 打印不规则数组
        System.out.println("不规则数组内容:");
        for (int i = 0; i < irregularArray.length; i++) {
            for (int j = 0; j < irregularArray[i].length; j++) {
                System.out.print(irregularArray[i][j] + " ");
            }
            System.out.println(); // 换行
        }
        
        System.out.println();
    }
    
    /**
     * 演示数组的遍历方式
     * 难点：不同遍历方式的选择和使用场景
     * 注意事项：
     * 1. 增强for循环简洁但无法获取索引
     * 2. 传统for循环可以控制遍历过程
     * 3. 使用迭代器遍历集合更安全
     */
    public void demonstrateArrayTraversal() {
        System.out.println("=== 数组遍历演示 ===");
        
        String[] fruits = {"苹果", "香蕉", "橙子", "葡萄", "西瓜"};
        
        // 方式1：传统for循环遍历（可以获取索引）
        System.out.println("使用传统for循环遍历:");
        for (int i = 0; i < fruits.length; i++) {
            System.out.println("索引" + i + ": " + fruits[i]);
        }
        
        // 方式2：增强for循环遍历（最简洁）
        System.out.println("\n使用增强for循环遍历:");
        for (String fruit : fruits) {
            System.out.println(fruit);
        }
        
        // 方式3：使用Arrays.toString()方法直接输出整个数组
        System.out.println("\n使用Arrays.toString()输出整个数组:");
        System.out.println(java.util.Arrays.toString(fruits));
        
        System.out.println();
    }
    
    /**
     * 演示Arrays工具类的使用
     * 难点：各种方法的功能和使用场景
     * 注意事项：
     * 1. Arrays类提供了大量操作数组的静态方法
     * 2. binarySearch方法要求数组事先排序
     * 3. equals方法比较的是数组元素而不是引用
     */
    public void demonstrateArraysUtility() {
        System.out.println("=== Arrays工具类演示 ===");
        
        int[] array1 = {3, 1, 4, 1, 5, 9, 2, 6};
        int[] array2 = {3, 1, 4, 1, 5, 9, 2, 6};
        int[] array3 = {1, 2, 3, 4, 5};
        
        // toString方法：将数组转换为字符串表示
        System.out.println("array1: " + java.util.Arrays.toString(array1));
        
        // sort方法：对数组进行排序
        java.util.Arrays.sort(array1);
        System.out.println("排序后的array1: " + java.util.Arrays.toString(array1));
        
        // binarySearch方法：二分查找（数组必须已排序）
        int index = java.util.Arrays.binarySearch(array1, 5);
        System.out.println("在array1中查找5的位置: " + index);
        
        // equals方法：比较两个数组是否相等
        System.out.println("array1和array2是否相等: " + java.util.Arrays.equals(array1, array2));
        System.out.println("array1和array3是否相等: " + java.util.Arrays.equals(array1, array3));
        
        // fill方法：用指定值填充数组
        int[] array4 = new int[5];
        java.util.Arrays.fill(array4, 7);
        System.out.println("用7填充的数组: " + java.util.Arrays.toString(array4));
        
        // copyOf方法：复制数组
        int[] array5 = java.util.Arrays.copyOf(array3, 10); // 扩展到10个元素
        System.out.println("扩展后的array3: " + java.util.Arrays.toString(array5));
        
        System.out.println();
    }
    
    /**
     * 演示数组常见算法（排序、查找等）
     * 难点：算法的实现和时间复杂度理解
     * 注意事项：
     * 1. 冒泡排序适合小规模数据
     * 2. 二分查找要求数据有序
     * 3. 实际开发中推荐使用Arrays工具类或集合框架
     */
    public void demonstrateArrayAlgorithms() {
        System.out.println("=== 数组常见算法演示 ===");
        
        int[] numbers = {64, 34, 25, 12, 22, 11, 90};
        System.out.println("原始数组: " + java.util.Arrays.toString(numbers));
        
        // 冒泡排序实现
        bubbleSort(numbers.clone());
        
        // 选择排序实现
        selectionSort(numbers.clone());
        
        // 线性查找
        int[] sortedNumbers = {11, 12, 22, 25, 34, 64, 90};
        linearSearch(sortedNumbers, 25);
        
        // 二分查找
        binarySearch(sortedNumbers, 25);
        
        System.out.println();
    }
    
    // 冒泡排序实现
    private void bubbleSort(int[] arr) {
        int n = arr.length;
        System.out.println("\n冒泡排序过程:");
        System.out.println("排序前: " + java.util.Arrays.toString(arr));
        
        for (int i = 0; i < n - 1; i++) {
            boolean swapped = false;
            for (int j = 0; j < n - i - 1; j++) {
                if (arr[j] > arr[j + 1]) {
                    // 交换元素
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                    swapped = true;
                }
            }
            System.out.println("第" + (i + 1) + "轮排序后: " + java.util.Arrays.toString(arr));
            // 如果没有发生交换，说明已经有序
            if (!swapped) break;
        }
        System.out.println("最终结果: " + java.util.Arrays.toString(arr));
    }
    
    // 选择排序实现
    private void selectionSort(int[] arr) {
        int n = arr.length;
        System.out.println("\n选择排序过程:");
        System.out.println("排序前: " + java.util.Arrays.toString(arr));
        
        for (int i = 0; i < n - 1; i++) {
            // 找到最小元素的索引
            int minIdx = i;
            for (int j = i + 1; j < n; j++) {
                if (arr[j] < arr[minIdx]) {
                    minIdx = j;
                }
            }
            
            // 交换最小元素到当前位置
            int temp = arr[minIdx];
            arr[minIdx] = arr[i];
            arr[i] = temp;
            
            System.out.println("第" + (i + 1) + "轮排序后: " + java.util.Arrays.toString(arr));
        }
        System.out.println("最终结果: " + java.util.Arrays.toString(arr));
    }
    
    // 线性查找
    private void linearSearch(int[] arr, int target) {
        System.out.println("\n线性查找:");
        System.out.println("在数组 " + java.util.Arrays.toString(arr) + " 中查找 " + target);
        
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] == target) {
                System.out.println("找到目标值 " + target + "，位置在索引 " + i);
                return;
            }
        }
        System.out.println("未找到目标值 " + target);
    }
    
    // 二分查找（数组必须已排序）
    private void binarySearch(int[] arr, int target) {
        System.out.println("\n二分查找:");
        System.out.println("在数组 " + java.util.Arrays.toString(arr) + " 中查找 " + target);
        
        int left = 0;
        int right = arr.length - 1;
        
        while (left <= right) {
            int mid = left + (right - left) / 2;
            
            if (arr[mid] == target) {
                System.out.println("找到目标值 " + target + "，位置在索引 " + mid);
                return;
            }
            
            if (arr[mid] < target) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        
        System.out.println("未找到目标值 " + target);
    }
    
    /**
     * 演示String类的特点和常用方法
     * 难点：字符串的不可变性和内存分配机制
     * 注意事项：
     * 1. String对象是不可变的，每次修改都会产生新对象
     * 2. 字符串常量存储在字符串常量池中
     * 3. 字符串比较应该使用equals方法而不是==
     */
    public void demonstrateStringBasics() {
        System.out.println("=== String类特点和常用方法演示 ===");
        
        // String的创建方式
        String str1 = "Hello";           // 字面量方式（存储在常量池中）
        String str2 = "Hello";           // 指向常量池中同一个对象
        String str3 = new String("Hello"); // new方式（在堆中创建新对象）
        String str4 = new String("Hello"); // new方式（在堆中创建新对象）
        
        System.out.println("str1 == str2: " + (str1 == str2));           // true，指向同一对象
        System.out.println("str3 == str4: " + (str3 == str4));           // false，不同的对象
        System.out.println("str1 == str3: " + (str1 == str3));           // false，不同区域的对象
        System.out.println("str1.equals(str3): " + (str1.equals(str3))); // true，内容相同
        
        // String常用方法演示
        String text = "Hello World Java";
        System.out.println("\n原字符串: " + text);
        System.out.println("字符串长度: " + text.length());
        System.out.println("第7个字符: '" + text.charAt(6) + "'");
        System.out.println("World的位置: " + text.indexOf("World"));
        System.out.println("最后一个o的位置: " + text.lastIndexOf('o'));
        System.out.println("替换World为Universe: " + text.replace("World", "Universe"));
        System.out.println("转为大写: " + text.toUpperCase());
        System.out.println("转为小写: " + text.toLowerCase());
        System.out.println("截取前5个字符: " + text.substring(0, 5));
        System.out.println("去除两端空格: '" + "  Hello Java  ".trim() + "'");
        
        // 难点演示：字符串不可变性
        System.out.println("\n字符串不可变性演示:");
        String original = "Hello";
        System.out.println("original = " + original);
        System.out.println("original的哈希码: " + original.hashCode());
        
        original = original + " World"; // 实际上创建了新的String对象
        System.out.println("修改后original = " + original);
        System.out.println("修改后original的哈希码: " + original.hashCode());
        
        System.out.println();
    }
    
    /**
     * 演示StringBuffer和StringBuilder的使用
     * 难点：三者的区别和适用场景
     * 注意事项：
     * 1. StringBuffer是线程安全的，StringBuilder不是
     * 2. 频繁字符串操作时推荐使用Buffer或Builder
     * 3. StringBuilder性能通常优于StringBuffer
     */
    public void demonstrateStringBufferBuilder() {
        System.out.println("=== StringBuffer和StringBuilder演示 ===");
        
        // StringBuffer演示（线程安全）
        StringBuffer stringBuffer = new StringBuffer("Hello");
        System.out.println("初始StringBuffer: " + stringBuffer);
        
        stringBuffer.append(" World");
        stringBuffer.append(" Java");
        System.out.println("追加后: " + stringBuffer);
        
        stringBuffer.insert(5, ",");
        System.out.println("插入逗号后: " + stringBuffer);
        
        stringBuffer.reverse();
        System.out.println("反转后: " + stringBuffer);
        
        stringBuffer.reverse(); // 再次反转恢复原状
        stringBuffer.delete(5, 6); // 删除逗号
        System.out.println("删除逗号后: " + stringBuffer);
        
        // StringBuilder演示（非线程安全，但性能更好）
        StringBuilder stringBuilder = new StringBuilder("Hello");
        System.out.println("\n初始StringBuilder: " + stringBuilder);
        
        stringBuilder.append(" World");
        stringBuilder.append(" Programming");
        System.out.println("追加后: " + stringBuilder);
        
        // 性能对比演示（简单版）
        System.out.println("\n简单性能对比:");
        long start, end;
        
        // String方式拼接
        start = System.currentTimeMillis();
        String str = "";
        for (int i = 0; i < 1000; i++) {
            str += "a";
        }
        end = System.currentTimeMillis();
        System.out.println("String拼接耗时: " + (end - start) + "ms");
        
        // StringBuilder方式拼接
        start = System.currentTimeMillis();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 1000; i++) {
            sb.append("a");
        }
        end = System.currentTimeMillis();
        System.out.println("StringBuilder拼接耗时: " + (end - start) + "ms");
        
        System.out.println();
    }
    
    /**
     * 演示字符串的比较和操作
     * 难点：equals、equalsIgnoreCase、compareTo等方法的区别
     * 注意事项：
     * 1. equals比较内容，==比较引用
     * 2. compareTo实现字典序比较
     * 3. 忽略大小写比较的正确方式
     */
    public void demonstrateStringOperations() {
        System.out.println("=== 字符串比较和操作演示 ===");
        
        String str1 = "Hello";
        String str2 = "hello";
        String str3 = "Hello";
        String str4 = new String("Hello");
        
        // 字符串比较
        System.out.println("str1 = \"" + str1 + "\"");
        System.out.println("str2 = \"" + str2 + "\"");
        System.out.println("str3 = \"" + str3 + "\"");
        System.out.println("str4 = \"" + str4 + "\"");
        
        System.out.println("\n字符串比较:");
        System.out.println("str1 == str2: " + (str1 == str2));                 // false
        System.out.println("str1 == str3: " + (str1 == str3));                 // true
        System.out.println("str1 == str4: " + (str1 == str4));                 // false
        System.out.println("str1.equals(str2): " + str1.equals(str2));         // false
        System.out.println("str1.equals(str3): " + str1.equals(str3));         // true
        System.out.println("str1.equals(str4): " + str1.equals(str4));         // true
        System.out.println("str1.equalsIgnoreCase(str2): " + str1.equalsIgnoreCase(str2)); // true
        
        // 字典序比较
        System.out.println("\n字典序比较:");
        System.out.println("str1.compareTo(\"Apple\"): " + str1.compareTo("Apple"));     // >0
        System.out.println("str1.compareTo(\"Hello\"): " + str1.compareTo("Hello"));     // =0
        System.out.println("str1.compareTo(\"World\"): " + str1.compareTo("World"));     // <0
        System.out.println("str1.compareToIgnoreCase(str2): " + str1.compareToIgnoreCase(str2)); // =0
        
        // 字符串分割和连接
        String sentence = "Java is a powerful programming language";
        System.out.println("\n原句子: " + sentence);
        
        String[] words = sentence.split(" ");
        System.out.println("分割后的单词:");
        for (String word : words) {
            System.out.println("- " + word);
        }
        
        String joined = String.join("-", words);
        System.out.println("用-连接: " + joined);
        
        System.out.println();
    }
    
    /**
     * 演示正则表达式基础
     * 难点：正则表达式的语法和特殊字符含义
     * 注意事项：
     * 1. 特殊字符需要转义
     * 2. Pattern和Matcher类提供更强大的功能
     * 3. 正则表达式在字符串验证和提取中很有用
     */
    public void demonstrateRegex() {
        System.out.println("=== 正则表达式基础演示 ===");
        
        // 基本匹配
        String email = "test@example.com";
        String phone = "138-1234-5678";
        String idCard = "123456789012345678";
        
        System.out.println("邮箱验证:");
        System.out.println(email + " 是有效邮箱? " + email.matches("\\w+@\\w+\\.\\w+"));
        
        System.out.println("\n手机号验证:");
        System.out.println(phone + " 是有效手机号? " + phone.matches("1[3-9]\\d-\\d{4}-\\d{4}"));
        
        System.out.println("\n身份证号验证:");
        System.out.println(idCard + " 是有效身份证号? " + idCard.matches("\\d{18}|\\d{17}[\\dXx]"));
        
        // 字符串替换
        String text = "联系电话：138-0000-1111，备用电话：139-1111-2222";
        System.out.println("\n原文本: " + text);
        String masked = text.replaceAll("1[3-9]\\d-\\d{4}-\\d{4}", "XXX-XXXX-XXXX");
        System.out.println("脱敏后: " + masked);
        
        // 字符串分割
        String data = "张三,25,工程师;李四,30,设计师;王五,28,产品经理";
        System.out.println("\n原始数据: " + data);
        String[] records = data.split(";");
        System.out.println("分割后的记录:");
        for (String record : records) {
            String[] fields = record.split(",");
            System.out.println("姓名: " + fields[0] + ", 年龄: " + fields[1] + ", 职业: " + fields[2]);
        }
        
        System.out.println();
    }
    
    /**
     * 演示字符串处理技巧
     * 难点：高效处理字符串的方法选择
     * 注意事项：
     * 1. 大量字符串操作时考虑使用StringBuilder
     * 2. 字符串格式化使用printf或format方法
     * 3. 字符串判空需要检查null和空字符串
     */
    public void demonstrateStringProcessing() {
        System.out.println("=== 字符串处理技巧演示 ===");
        
        // 字符串格式化
        String name = "张三";
        int age = 25;
        double salary = 8500.50;
        
        System.out.println("使用printf格式化输出:");
        System.out.printf("姓名：%s，年龄：%d，薪资：%.2f%n", name, age, salary);
        
        String formatted = String.format("姓名：%s，年龄：%d，薪资：%.2f", name, age, salary);
        System.out.println("使用format方法: " + formatted);
        
        // 字符串判空处理
        System.out.println("\n字符串判空处理:");
        String nullStr = null;
        String emptyStr = "";
        String blankStr = "   ";
        String normalStr = "Hello";
        
        System.out.println("null字符串是否为空: " + (nullStr == null || nullStr.isEmpty()));
        System.out.println("空字符串是否为空: " + (emptyStr == null || emptyStr.isEmpty()));
        System.out.println("空白字符串是否为空: " + (blankStr == null || blankStr.isEmpty()));
        System.out.println("正常字符串是否为空: " + (normalStr == null || normalStr.isEmpty()));
        
        System.out.println("null字符串是否为空白: " + (nullStr == null || nullStr.trim().isEmpty()));
        System.out.println("空字符串是否为空白: " + (emptyStr == null || emptyStr.trim().isEmpty()));
        System.out.println("空白字符串是否为空白: " + (blankStr == null || blankStr.trim().isEmpty()));
        System.out.println("正常字符串是否为空白: " + (normalStr == null || normalStr.trim().isEmpty()));
        
        // 统计字符出现次数
        String text = "Hello Java Programming";
        System.out.println("\n统计字符出现次数:");
        System.out.println("文本: " + text);
        System.out.println("字母'a'出现次数: " + countChar(text, 'a'));
        System.out.println("字母'l'出现次数: " + countChar(text, 'l'));
        
        // 反转字符串
        System.out.println("\n字符串反转:");
        System.out.println("原字符串: " + text);
        System.out.println("反转后: " + reverseString(text));
        
        // 回文检测
        String palindrome1 = "level";
        String palindrome2 = "hello";
        System.out.println("\n回文检测:");
        System.out.println(palindrome1 + " 是回文? " + isPalindrome(palindrome1));
        System.out.println(palindrome2 + " 是回文? " + isPalindrome(palindrome2));
        
        System.out.println();
    }
    
    // 统计字符出现次数
    private int countChar(String text, char ch) {
        int count = 0;
        for (int i = 0; i < text.length(); i++) {
            if (text.charAt(i) == ch) {
                count++;
            }
        }
        return count;
    }
    
    // 反转字符串
    private String reverseString(String str) {
        return new StringBuilder(str).reverse().toString();
    }
    
    // 回文检测
    private boolean isPalindrome(String str) {
        String cleaned = str.toLowerCase();
        int left = 0;
        int right = cleaned.length() - 1;
        
        while (left < right) {
            if (cleaned.charAt(left) != cleaned.charAt(right)) {
                return false;
            }
            left++;
            right--;
        }
        return true;
    }
}